#include "IContainer.h"
#include "IBusiness.h"
#include <list>
#include <vector>
#include <string.h>
#include "ILogger.h"
class SimpleProtoDecode : public IProtoDecode {
public:
    virtual void put(const char *buf,int len) {
        for (int i = 0; i < len; ++i) {
            buffer.push_back(buf[i]);
            if (buffer.size() >= 4) {
                packageSize = *(int*)& buffer[0];
                if ((int)buffer.size() == packageSize + 4) {
                    std::string package;
                    package.resize(packageSize);
                    memcpy(&package[0],&buffer[4],packageSize);
                    packages.push_back(package);
                    LogI("package.size():%d strSize:%d",package.size(),*(int*)& package[0]);
                    buffer.clear();
                }
            }

        }
    }
    virtual int getPackage(const char *buf,int len) {
         if (packages.size() > 0) {
            std::string msg = packages.front();
            memcpy((void*)buf,&msg[0],msg.size());
            LogI("msg.size():%d strSize:%d",msg.size(),*(int*)buf);
            packages.pop_front();
            return msg.size();
         }
         return -1;
    }
    std::string buffer;
    std::list<std::string> packages;
    int packageSize;
};

class SimpleProtoEncode : public IProtoEncode {
public:
    virtual void encode(const char *buf,int len) {
        _content.resize(len + 4);
        memcpy(&_content[0],&len,4);
        memcpy(&_content[4],buf,len);
    }
    virtual void *content(){
        return &_content[0];
    }
    virtual int size() {
        return _content.size();
    }
    virtual void clear(){
        _content.clear();
    }
    std::string _content;
};

/**
 * @brief a simple container to contain business,decoder,encoder
 *   <bean name="domain_server" interface="IContainer" implemation="SimpleBusinessContainer">
 *       <server implemation="DomainServerServlet">
 *           <connection name="server" url="/tmp/domain_ss"/>
 *       </server>
 *       <business implemation="CameraDiagServletImp"/>
 *       <encode implemation="SimpleProtoEncode"/>
 *       <decode implemation="SimpleProtoDecode"/>
 *   </bean>
 */
class BusinessContainerSessionExtern : public ISession ,public IServlet{
public:
    virtual void onMessage(ISession *session,void* content,int len) {};
    virtual void onState(SERVLET_STATUS status,int code){}
    virtual void request(const void *data,int len) {
        LogI("server request len:%d",len);
        SimpleProtoEncode encode;
        encode.encode((char*)data,len);
        session->reply(encode.content(),encode.size());
    };
    virtual void start() {};
    virtual void wait() {};
    virtual void stop() {};

     virtual IPlugin *getBusiness(const char *name) {
        return (IPlugin*) session->getComponent(name);
    };
    
    virtual IServlet *getServlet() {
        return this;
    }
    BusinessContainerSessionExtern(ISession *session,IContainer *container) 
        : session(session),container(container) {

    }
    virtual void reply(const void *data,int len) {}
    virtual void close() {}
private:
    ISession *session;
    IContainer*container;
};

class BusinessClientSessionExtern : public ISession ,public IServlet{
public:
    virtual void onMessage(ISession *session,void* content,int len) {};
    virtual void onState(SERVLET_STATUS status,int code){}
    virtual void request(const void *data,int len) {
        LogI("client request len:%d",len);
        SimpleProtoEncode encode;
        encode.encode((char*)data,len);
        container->getServlet()->request(encode.content(),encode.size());
    };
    virtual void start() {};
    virtual void wait() {};
    virtual void stop() {};

     virtual IPlugin *getBusiness(const char *name) {
        return (IPlugin*) session->getComponent(name);
    };
    
    virtual IServlet *getServlet() {
        return this;
    }
    BusinessClientSessionExtern(ISession *session,IContainer *container) 
        : session(session),container(container) {

    }
    virtual void reply(const void *data,int len) {}
    virtual void close() {}
private:
    ISession *session;
    IContainer*container;
};
class SimpleBusinessContainer : public IContainer {
public:
    void onLoad(INode *node)
    {
        INode *child = node->childNode(NULL);
        while (child) {
            std::string implemation = child->getStr("implemation");
             std::string interface = child->getStr("interface");
            if (child->name == "server") {
                server= (IServlet*)IPlugin::loadPlugin(implemation.c_str());
                server->onLoad(child);
            }
         
            if (child->name == "business") {
                IBusiness *bean = (IBusiness*)IPlugin::loadPlugin(implemation.c_str());
                bean->onLoad(node);
                bean->next = businessList;
                businessList = bean;
            }
           

            child = child->nextNode(NULL);
        }
   
        server->on(STREAM,[=](ISession *session,void * data,int len)->int{
            BusinessContainerSessionExtern sessionExt(session,this);
            IProtoDecode *decode = session->addComponent<SimpleProtoDecode>("decode");
            // 将session 的能力拓展
            // 可以有获取business 能力
            // 可以有servlet能力
            this->onMessage(decode,&sessionExt,data,len);
            return 0;
        });
        server->on(OPEN,[=](ISession *session,void*,int)->int {
            // 为session 赋值 business
            IBusiness *iterator = this->businessList;
            while (iterator) {
                iterator->copyTo(*session->getAlloc(iterator->getBusinessName()));
                iterator->onOpen(session);
                iterator = iterator->next;
            }
            return 0;
        });
        server->on(CLOSE,[=](ISession *session,void*,int)->int {
            // 为session 赋值 business
            IBusiness *iterator = this->businessList;
            while (iterator) {
                iterator->onClose(session);
                iterator = iterator->next;
            }
            return 0;
        });
        server->on(ERROR,[=](ISession *session,void* data,int code)->int {
            // 为session 赋值 business
            IBusiness *iterator = this->businessList;
            while (iterator) {
                iterator->onError(session,code);
                iterator = iterator->next;
            }
            return 0;
        });
    }
  

    void onMessage(IProtoDecode *decode,ISession *session,void* content,int len)
    {
        LogI("len:%d",len);
        decode->put((const char *)content,len);
        char *buffer = new char[4026];
        while((len = decode->getPackage(buffer,4026)) != -1) {
            LogI("parse package %d",len);
            IBusiness *iterator = this->businessList;
            while (iterator) {
                iterator->dispatchActions(session,buffer,len);
                iterator = iterator->next;
            }
        }
        delete[] buffer;
    }
    void on(SERVLET_STATUS type,std::function<int(ISession *)> handler)
    {
        server->on(OPEN,[=](ISession *session,void*,int) ->int{
            BusinessContainerSessionExtern sessionExt(session,this);
            session->addComponent<SimpleProtoDecode>("decode");
            handler(&sessionExt);
            return 0;
        });
    }
    IServlet *getServlet() {
        return server;
    }
    void onUnload(){
        LogI("onUnload");
        server->onUnload();
    }
    SimpleBusinessContainer() {
        businessList = NULL;
        server = NULL;
    }
private:
    IBusiness *businessList;
    IServlet *server;
};


class SimpleBusinessClient : public IContainer {
public:
    void onLoad(INode *node)
    {
        INode *child = node->childNode(NULL);
        while (child) {
            std::string implemation = child->getStr("implemation");
            std::string interface = child->getStr("interface");
            if (child->name == "client") {
                client= (IServlet*)IPlugin::loadPlugin(implemation.c_str());
                client->onLoad(child);
            }
         
            if (child->name == "business") {
                IBusiness *bean = (IBusiness*)IPlugin::loadPlugin(implemation.c_str());
                bean->onLoad(node);
                bean->next = businessList;
                businessList = bean;
            }
      


            child = child->nextNode(NULL);
        }
   
        client->on(STREAM,[=](ISession *session,void * data,int len)->int{
            // 将session 的能力拓展
            // 可以有获取business 能力
            // 可以有servlet能力
            BusinessClientSessionExtern sessionExt(session,this);
            IProtoDecode *decode = session->addComponent<SimpleProtoDecode>("decode");
            this->onMessage(decode,&sessionExt,data,len);
            
            return 0;
        });
        client->on(CLOSE,[=](ISession *session,void*,int)->int {
            // 为session 赋值 business
            IBusiness *iterator = this->businessList;
            while (iterator) {
                iterator->onClose(session);
                iterator = iterator->next;
            }
            return 0;
        });
        client->on(ERROR,[=](ISession *session,void* data,int code)->int {
            // 为session 赋值 business
            IBusiness *iterator = this->businessList;
            while (iterator) {
                iterator->onError(session,code);
                iterator = iterator->next;
            }
            return 0;
        });
        client->on(OPEN,[=](ISession *session,void*,int) ->int{
            IBusiness *iterator = this->businessList;
            while (iterator) {
                iterator->copyTo(*session->getAlloc(iterator->getBusinessName()));
                iterator->onOpen(session);
                iterator = iterator->next;
            }
            return 0;
        });
    }
  

    void onMessage(IProtoDecode *decode,ISession *session,void* content,int len)
    {
        //LogI("client len:%d",len);
        decode->put((const char *)content,len);
        char *buffer = new char[4026];
        while((len = decode->getPackage(buffer,4026)) != -1) {
            //LogI("client get package");
            IBusiness *iterator = this->businessList;
            while (iterator) {
                iterator->dispatchActions(session,buffer,len);
                iterator = iterator->next;
            }
        }
        delete[] buffer;
    }

    IServlet *getServlet() {
        return client;
    }

     void onUnload(){
        LogI("onUnload");
        client->onUnload();
    }

    void on(SERVLET_STATUS type,std::function<int(ISession *)> handler)
    {
        client->on(OPEN,[=](ISession *session,void*,int) ->int{
            BusinessClientSessionExtern sessionExt(session,this);
            session->addComponent<SimpleProtoDecode>("decode");
            handler(&sessionExt);
            return 0;
        });
    }
private:
    IBusiness *businessList;
    IServlet *client;
};

REG_PLUGIN(SimpleBusinessContainer)
REG_PLUGIN(SimpleProtoDecode)
REG_PLUGIN(SimpleProtoEncode)
REG_PLUGIN(SimpleBusinessClient)
